package com.niiwoo.civet.user.service.duboo;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dangdang.ddframe.rdb.sharding.api.HintManager;
import com.dangdang.ddframe.rdb.sharding.hint.HintManagerHolder;
import com.google.common.base.Splitter;
import com.niiwoo.activity.event.constant.BizEventRabbitConstant;
import com.niiwoo.activity.event.dto.request.RecommendEventReqDTO;
import com.niiwoo.activity.event.dto.request.RegisterEventReqDTO;
import com.niiwoo.activity.stage.constant.ActivityRabbitConstant;
import com.niiwoo.activity.stage.dto.request.channel.DraingeChannelUseAddReqDTO;
import com.niiwoo.activity.stage.dto.request.notice.NoviceTaskRecordRequestDTO;
import com.niiwoo.activity.stage.enums.activity.NoviceTaskPrizeEnum;
import com.niiwoo.activity.stage.enums.channel.OsTyprEnum;
import com.niiwoo.activity.stage.service.invite.InviteFriendInfoDubboService;
import com.niiwoo.civet.system.service.SysParamService;
import com.niiwoo.civet.trade.constant.RabbitConstant;
import com.niiwoo.civet.trade.enums.ChannelCodeEnum;
import com.niiwoo.civet.user.constants.LoginAccountErrorCode;
import com.niiwoo.civet.user.constants.UserRabbitConstant;
import com.niiwoo.civet.user.dao.entity.*;
import com.niiwoo.civet.user.dao.mapper.*;
import com.niiwoo.civet.user.dto.CallOutTaskAddReqDTO;
import com.niiwoo.civet.user.dto.request.*;
import com.niiwoo.civet.user.dto.response.*;
import com.niiwoo.civet.user.enums.*;
import com.niiwoo.civet.user.enums.UserEnum.RegisterDeviceType;
import com.niiwoo.civet.user.service.UserLoginAccountDubboService;
import com.niiwoo.civet.user.service.local.*;
import com.niiwoo.civet.user.service.local.dataflow.UserDataBackFlowService;
import com.niiwoo.civet.user.service.local.notify.PersonalizedNotifyUserLocalService;
import com.niiwoo.civet.user.service.local.sms.SMSSenders;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.base.helper.StringHelper;
import com.niiwoo.tripod.im.component.IMService;
import com.niiwoo.tripod.im.request.UpdateUserInfoRequest;
import com.niiwoo.tripod.im.response.NiiwooNumberResponse;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import com.niiwoo.tripod.tiancheng.component.TianchengVerNameService;
import com.niiwoo.tripod.tiancheng.enums.FunctionCodeEnum;
import com.niiwoo.tripod.tiancheng.request.df.LoginSuccessRequest;
import com.niiwoo.tripod.tiancheng.request.df.RegisterSuccessRequest;
import com.niiwoo.tripod.tiancheng.request.qdp.KaoLaVerNameRequset;
import com.niiwoo.tripod.tiancheng.request.qdp.VerNameRequset;
import com.niiwoo.tripod.tiancheng.response.qdp.KaoLaVerNameResponse;
import com.niiwoo.tripod.tiancheng.response.qdp.VerNameResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.Duration;
import org.joda.time.LocalDate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.time.Instant;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.niiwoo.civet.user.service.local.LoginAccountRedisService.LOGIN_PASSWORD_ERROR_TIMES_FORMAT;

/**
 * 用户登录账号API实现
 */
@Service(version = "1.0.0")
@Slf4j
public class UserLoginAccountDubboServiceImpl implements UserLoginAccountDubboService, UserSystemConfigurable {

    @Autowired
    UserLoginAccountService userLoginAccountLocalService;

    @Autowired
    SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    UserForbidService userForbidService;

    @Autowired
    PrivacyMasks privacyMasks;

    @Reference(version = "1.0.0")
    SysParamService sysParamService;

    @Reference(version = "1.0.0")
    InviteFriendInfoDubboService inviteFriendInfoDubboService;

//    @Reference(version = "1.0.0")
//    FyUserInfoDubboService fyUserInfoDubboService;

    @Autowired
    UserDataBackFlowService userDataBackFlowService;

    @Autowired
    UserExtInfoMapperExt userExtInfoMapper;

    @Autowired
    IMService imService;

    @Autowired
    UserStatusService userStatusService;

    @Autowired
    IdentityMappingService identityMappingService;

    @Autowired
    UserIdentityService userIdentityService;

    @Autowired
    AccountExtendMapperExt accountExtendMapperExt;

    @Autowired
    UserBasicInfoMapperExt userBasicInfoMapperExt;

    @Autowired
    LoginAccountMappingMapper loginAccountMappingMapper;
    
    @Autowired
    private UserInviteCodeMapperExt userInviteCodeMapperExt;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private UserNickNameLibraryMapper userNickNameLibraryMapper;

    @Autowired
    SMSSenders smsSender;

    @Autowired
    TianchengVerNameService tianchengVerNameService;

    @Autowired
    private PersonalizedNotifyUserLocalService personalizedNotifyUserLocalService;

    @Value("${niiwoo-wechat-account}")
    private String wechatAccount;

    private static String DEFAULT_SCORE_DETAIL = "{\"EngagementAbility\":\"0.00\",\"CreditHistory\":\"0.00\",\"GuanXi\":\"0.00\",\"Behavior\":\"0.00\",\"IdFeature\":\"0.00\"}";

    @Override
    public AccountMappingDTO queryAccountMapping(String accountName) {
        LoginAccountMapping loginAccountMapping = loginAccountMappingMapper.selectByPrimaryKey(accountName);
        AccountMappingDTO accountMappingDTO = null;
        if(loginAccountMapping!=null){
            accountMappingDTO = new AccountMappingDTO();
            accountMappingDTO.setUserId(loginAccountMapping.getUserId());
            accountMappingDTO.setAccountName(loginAccountMapping.getAccountName());
        }
        return accountMappingDTO;
    }


    /**
     * 融360自动注册/实名认证
     *
     * @param registerRequest
     * @return
     */

    public UserAutoRegisterDto autoRegister(AutoRegisterAndIdentityDto registerRequest) {
        log.info("R360用户注册，用户信息为:{}",JSON.toJSONString(registerRequest));
        UserAutoRegisterDto result = new UserAutoRegisterDto(UserAutoRegisterDto.SUCCESS_RET, UserAutoRegisterDto.SUCCESS_RET_MSG);
        // 注册来源不能为空
        if (registerRequest.getRegisterChannel() == null) {
            result.setRet(UserAutoRegisterDto.FAIL_RET);
            result.setMessage("注册来源不能为空");
            return result;
        }
        String userId;
        // 加密登录手机号
        final String encryptMobileNo = getEncryptMobileNo(registerRequest.getLoginMobileNo());
        // 校验用户是否存在
        LoginAccountMapping loginAccountMapping = userLoginAccountLocalService.getAccountMapping(encryptMobileNo);
        if (loginAccountMapping == null) {
            log.info("R360用户{}不存在，第一次推送信息",registerRequest.getLoginMobileNo());
            if (identityMappingService.isExists(ecryptIdCard(registerRequest.getIdCardNo()))) {
                result.setRet(UserAutoRegisterDto.FAIL_RET);
                result.setMessage("手机号码未注册，但用户信息已存在你我，拒绝注册");
                return result;
            }

            if (!verifyIdNameByPengYuan(registerRequest.getName(), registerRequest.getIdCardNo())) {
                result.setRet(UserAutoRegisterDto.FAIL_RET);
                result.setMessage("实名认证不通过");
                return result;
            }

            log.info("R360用户{}数据第一次推送信息，实名验证通过",registerRequest.getLoginMobileNo());
            userId = autoRegist(registerRequest, encryptMobileNo);
            // 失败
            if (String.valueOf(UserAutoRegisterDto.FAIL_RET).equals(userId)) {
                result.setRet(UserAutoRegisterDto.FAIL_RET);
                result.setMessage("注册失败");
                result.setErrorCode(UserAutoRegisterDto.ERROR_CODE_REGIST);
                return result;
            }
            boolean verifyInfo = userIdentityService.tryUpdateAuthInfoByReamNameAuth(userId,registerRequest.getName(),
                    privacyMasks.encryptPrivacy(registerRequest.getIdCardNo()),registerRequest.getIdCardNo());
            if(!verifyInfo){
                log.info("R360实名认证成功,用户已经注册，认证信息同步失败");
                result.setRet(UserAutoRegisterDto.FAIL_RET);
                result.setMessage("R360实名认证成功,用户已经注册，认证信息同步失败");
                result.setErrorCode(UserAutoRegisterDto.ERROR_CODE_REGIST);
            }
            log.info("R360用户{}数据第一次推送信息，实名验证通过，数据插入成功",registerRequest.getLoginMobileNo());
        } else {
            log.info("R360用户手机号已存在");
            DataStatus dataStatus = userStatusService.getByUserIdAndType(loginAccountMapping.getUserId(), UserDataTypeEnum.TWO_ELEMENT);
            if (dataStatus != null && dataStatus.getDataStatus().equals(UserDataStatusEnum.RealNameAuthStatus.PASS_CERTIFIED.getStatus()) ) {
                log.info("R360用户手机号存在,且实名认证通过");
                if (!ecryptIdCard(registerRequest.getIdCardNo()).equals(userIdentityService.getByUserId(loginAccountMapping.getUserId()).getIdCard())
                        || !registerRequest.getName().equals(userIdentityService.getByUserId(loginAccountMapping.getUserId()).getName())) {
                    result.setRet(UserAutoRegisterDto.FAIL_RET);
                    result.setMessage("手机号码已注册已实名，但用户信息与你我金融身份信息不一致，拒绝用户");
                    return result;
                }
                log.info("手机号码{}已注册已实名，但用户信息与你我金融身份信息一致",registerRequest.getLoginMobileNo());
            } else {
                log.info("R360用户手机号{}存在,且未做实名认证",registerRequest.getLoginMobileNo());
                if (identityMappingService.isExists(ecryptIdCard(registerRequest.getIdCardNo()))) {
                    result.setRet(UserAutoRegisterDto.FAIL_RET);
                    result.setMessage("手机号码已注册未实名，但用户信息已存在你我金融，拒绝用户");
                    return result;
                } else {
                    log.info("R360用户手机号{}存在,且未做实名认证，身份证信息不存在，开始实名认证",registerRequest.getLoginMobileNo());
                    // 实名认证(通过自动注册、失败拒绝用户)

                    if (!verifyIdNameByPengYuan(registerRequest.getName(), registerRequest.getIdCardNo())) {
                        result.setRet(UserAutoRegisterDto.FAIL_RET);
                        result.setMessage("实名认证不通过");
                        return result;
                    }

                    log.info("R360用户手机号{}存在,且未做实名认证，身份证信息不存在，实名认证通过开始插入同步信息",registerRequest.getLoginMobileNo());
                    boolean verifyInfo = userIdentityService.tryUpdateAuthInfoByReamNameAuth(loginAccountMapping.getUserId(),registerRequest.getName(),
                            privacyMasks.encryptPrivacy(registerRequest.getIdCardNo()),registerRequest.getIdCardNo());
                    if(!verifyInfo){
                        log.info("R360实名认证成功,用户已经注册，认证信息同步失败");
                        result.setMessage("R360实名认证成功,用户已经注册，认证信息同步失败");
                        result.setRet(UserAutoRegisterDto.FAIL_RET);
                        result.setErrorCode(UserAutoRegisterDto.ERROR_CODE_REGIST);
                    }
                    log.info("R360用户{}数据同步通过",registerRequest.getLoginMobileNo());
                }
            }
            userId = loginAccountMapping.getUserId();
        }

        //个人实名信息回流
        CompletableFuture.runAsync(() -> userDataBackFlowService.identityRealInfoBackFlow(userId));

        result.setData(userId);

        return result;
    }

    @Override
    public void resetLoginPwdByOldOne(LoginPwdSelfResetPwdRequestDTO requestDTO) {
        UcAccount ucAccount = new UcAccount();
        ucAccount.setUserId(requestDTO.getUserId());
        ucAccount.setPassword(requestDTO.getNewPassword());
        ucAccount.setSalt(requestDTO.getSlat());
        if (!userLoginAccountLocalService.updateLoginAccountInfo(ucAccount)) {
            throw new BizException(LoginAccountErrorCode.RESET_LOGIN_PASSWORD_FAIL);
        }
    }

    @Override
    public LoginAccountResponseDTO getLoginAccount(String userId) {
        LoginAccountResponseDTO responseDTO = new LoginAccountResponseDTO();
        UcAccount ucAccount = userLoginAccountLocalService.getAccountByUserId(userId);
        responseDTO.setSlat(ucAccount.getSalt());
        responseDTO.setPassword(ucAccount.getPassword());
        responseDTO.setLoginMobileNo(ucAccount.getMobileNo());
        responseDTO.setUserId(ucAccount.getUserId());
        return responseDTO;
    }

    /**
     * 校验短信验证码
     *
     * @param mobileNo
     * @param smsCode
     * @return
     */
    @Override
    public boolean validSMSCode(String mobileNo, String smsCode, UserSMSTypeEnum smsType) {
        if (!smsSender.isAuthCodeCacheRight(smsType, mobileNo, smsCode)) {
            throw new BizException(LoginAccountErrorCode.SMS_CODE_ERROR);
        }
        return true;
    }

    /**
     * 校验注册短信验证码
     * @param mobileNo
     * @param smsCode
     * @return
     */
    @Override
    public String validRegisterSMSCode(String mobileNo, String smsCode, UserSMSTypeEnum smsType) {
        //  "1";//代表验证成功  "3"; //代表过期或验证失败
        return smsSender.isAuthCodeCacheRight(smsType, mobileNo, smsCode) ? "1" : "3";
    }

    /**
     * 获取有效的昵称
     * @param nickName
     * @return
     */
    @Override
    public String getValidNickName(String nickName){
        for(int i = 1; i<10; i++) {
            UserNickNameLibrary userNickNameLibrary = userNickNameLibraryMapper.selectByPrimaryKey(nickName);
            if(userNickNameLibrary == null){
                break;
            }else if(i == 1){
                nickName = nickName + "_" + i;
            }else if(i == 9){
                nickName = generateNiiwooNickname();
            }else {
                nickName = nickName.substring(0,nickName.length()-1) + i;
            }
        }
        return nickName;
    }

    /**
     * 插入昵称库
     */
    @Override
    public void insertNickName(String nickName){
        UserNickNameLibrary userNickNameLibrary = new UserNickNameLibrary();
        userNickNameLibrary.setNickName(nickName);
        userNickNameLibrary.setUpdateTime(new Date());
        userNickNameLibraryMapper.insertSelective(userNickNameLibrary);
    }

    private static class EntityBuilder {

        static LoginAccountMapping buildLoginAccountMapping(String userId, String encryptMobileNo) {
            LoginAccountMapping accountMapping = new LoginAccountMapping();
            accountMapping.setAccountName(encryptMobileNo);
            accountMapping.setUserId(userId);
            return accountMapping;
        }

        static UcAccount buildLoginAccount(LoginAccountMapping mapping, String salt, String password) {
            UcAccount account = new UcAccount();
            account.setUserId(mapping.getUserId());
            account.setMobileNo(mapping.getAccountName());
            account.setSalt(salt);
            account.setPassword(password);
            account.setCreateTime(new Date());
            return account;
        }

        static UserBasicInfo buildLoginAccountBasicInfo(LoginAccountMapping mapping, UserEnum.RegisterChannel registerChannel,Boolean isInvest,
                                                        String nickName, String headImage, Function<UserBasicInfo, String> f) {
            UserBasicInfo basicInfo = new UserBasicInfo();
            basicInfo.setUserId(mapping.getUserId());
            basicInfo.setMobileNo(mapping.getAccountName());
            basicInfo.setRegisterChannel(registerChannel.getValue());
            basicInfo.setNiiwooScore(300); //初始化用户你我分为300
            basicInfo.setNickName(nickName);
            basicInfo.setHeadImage(headImage);
            basicInfo.setGender((byte)UserEnum.Gender.UNKNOWN.getValue());
            basicInfo.setPersonalSign("");
            basicInfo.setCreateTime(new Date());
            basicInfo.setIdentityTag(UserEnum.IdentityTag.NO_IDENTITY.getType());
            basicInfo.setNiiwooCode(f.apply(basicInfo));
            basicInfo.setWindowFlag((byte)0);
            basicInfo.setUserSeletctInvestLoanTag(isInvest == null ? (byte) 0 : (isInvest ? (byte) 1 : (byte) 2));
            return basicInfo;
        }

        static UserExtInfo buildLoginAccountExtInfo(LoginAccountMapping mapping, LoginAccountRegisterRequestDTO requestDTO) {
            UserExtInfo extInfo = new UserExtInfo();
            extInfo.setUserId(mapping.getUserId());
            extInfo.setAppDownloadChannel(requestDTO.getAppDownloadChannel());
            extInfo.setRegisterProvince(requestDTO.getProvinceName());
            extInfo.setRegisterCity(requestDTO.getCityName());
            extInfo.setRegisterArea(requestDTO.getAreaName());
            extInfo.setRegisterAddress(requestDTO.getAddress());
            extInfo.setRegisterLongitude(requestDTO.getLongitude());
            extInfo.setRegisterLatitude(requestDTO.getLatitude());
            extInfo.setDeviceType(requestDTO.getDeviceType().getValue());
            extInfo.setAppVersion(requestDTO.getAppVersion());
            extInfo.setJiGuangPushId(requestDTO.getJiGuangPushId());
            extInfo.setCreateTime(new Date());
            return extInfo;
        }

        /**
         * 自动注册时,请求DTO携带的额外信息可以在此添加
         * @param mapping
         * @param assetAutoRegisterBaseReqDTO
         * @return
         */
        static UserExtInfo buildLoginAccountExtInfo(LoginAccountMapping mapping, AssetAutoRegisterBaseReqDTO assetAutoRegisterBaseReqDTO) {
            AssetUserExtInfoDTO assetUserExtInfo;
            if(Objects.isNull(assetUserExtInfo = assetAutoRegisterBaseReqDTO.getAssetUserExtInfoDTO())){
                return buildLoginAccountExtInfo(mapping);
            }
            else{
                /*
                 * 卡牛自动注册时,t_uc_ext_info表插入的数据来自于个人信息中的设备信息项
                 * 其他渠道自动注册时,t_uc_ext_info表插入的数据请在资产端自行填充到AssetUserExtInfoDTO实体中
                 */
                Date now = new Date();
                UserExtInfo  extInfo = new UserExtInfo();
                extInfo.setUserId(mapping.getUserId());
                extInfo.setRegisterProvince(assetUserExtInfo.getProvinceName());
                extInfo.setRegisterArea(assetUserExtInfo.getAreaName());
                extInfo.setRegisterCity(assetUserExtInfo.getCityName());
                extInfo.setRegisterAddress(assetUserExtInfo.getAddress());
                extInfo.setRegisterLatitude(assetUserExtInfo.getLatitude());
                extInfo.setRegisterLongitude(assetUserExtInfo.getLongitude());
                extInfo.setDeviceType(assetUserExtInfo.getDeviceType() == null ? null : assetUserExtInfo.getDeviceType().getValue());
                extInfo.setCreateTime(now);
                extInfo.setUpdateTime(now);
                return extInfo;
            }
        }


        static UserExtInfo buildLoginAccountExtInfo(LoginAccountMapping mapping) {
            UserExtInfo extInfo = new UserExtInfo();
            extInfo.setUserId(mapping.getUserId());
            extInfo.setCreateTime(new Date());
            return extInfo;
        }

        static UserAuthorizationInfo buildLoginAccountAuthorizationInfo(LoginAccountMapping mapping) {
            UserAuthorizationInfo authorizationInfo = new UserAuthorizationInfo();
            authorizationInfo.setUserId(mapping.getUserId());
            authorizationInfo.setZhimaFailureReason("");
            authorizationInfo.setSocialSecurityAuthCity("");
            authorizationInfo.setFadadaCacertId("");
            authorizationInfo.setCreateTime(new Date());
            return authorizationInfo;
        }

         static NiiwooScore buildNiiwooScore(long id, LoginAccountMapping mapping) {
             NiiwooScore score = new NiiwooScore();
             score.setId(id);
             score.setUserId(mapping.getUserId());
             score.setScore(300);
             score.setScoreDetail(DEFAULT_SCORE_DETAIL);
             score.setEvaluateTime(new Date());
             score.setCreateTime(new Date());
             score.setEvaluateTime(new Date());
             return score;
        }

    }

    /**
     * 注册
     */
    @Override
    public String register(LoginAccountRegisterRequestDTO requestDTO) {
        // 加密登录手机号
        final String encryptMobileNo = getEncryptMobileNo(requestDTO.getLoginMobileNo());
        // 校验用户是否存在
        if (userLoginAccountLocalService.isExists(encryptMobileNo)) {
            throw new BizException(LoginAccountErrorCode.USERS_ALREADY_EXIST);
        }
        // 账号映射
        LoginAccountMapping accountMapping = EntityBuilder.buildLoginAccountMapping(UUID.randomUUID().toString(), encryptMobileNo);
        // 账号
        UcAccount account = EntityBuilder.buildLoginAccount(accountMapping, requestDTO.getSalt(), requestDTO.getPassword());
        // 基础信息
        UserBasicInfo basicInfo = EntityBuilder.buildLoginAccountBasicInfo(
                                                                            accountMapping,
                                                                            requestDTO.getRegisterChannel(),
                                                                            requestDTO.getIsInvest(),
                                                                            StringUtils.defaultIfBlank(requestDTO.getNickName(), generateNiiwooNickname()),
                                                                            StringUtils.defaultIfBlank(requestDTO.getHeadImage(), randomGetSystemHeader()),
                                                                            i -> {
                                                                                UpdateUserInfoRequest r = new UpdateUserInfoRequest();
                                                                                r.setGuid(String.valueOf(i.getUserId()));
                                                                                r.setMobile(requestDTO.getLoginMobileNo());
                                                                                r.setPassword(requestDTO.getPassword());
                                                                                r.setNickname(i.getNickName());
                                                                                r.setAvatar(i.getHeadImage());
                                                                                r.setGender(i.getGender());
                                                                                return updateUserInfoIM(r);
                                                                            }
                                                                        );
        // 扩展信息
        UserExtInfo extInfo = EntityBuilder.buildLoginAccountExtInfo(accountMapping, requestDTO);
        // 你我分
        NiiwooScore score  =  EntityBuilder.buildNiiwooScore(snowflakeIdWorker.nextId(), accountMapping);
        // 邀请关系
        String inviterUserId = null;
        if (requestDTO.getInviterUserId() != null) {
            inviterUserId = Optional.ofNullable(userLoginAccountLocalService.getAccountByUserId(requestDTO.getInviterUserId()))
                                    .map(UcAccount::getUserId)
                                    .orElse(null);
        } else if (StringUtils.isNotBlank(requestDTO.getInviterMobileNo())) {
        	// 按照手机号码查询
            inviterUserId = Optional.ofNullable(userLoginAccountLocalService.getAccountMapping(getEncryptMobileNo(requestDTO.getInviterMobileNo())))
                            .map(LoginAccountMapping::getUserId).orElse(null);
            
            // 手机号码不存在，按照邀请码查询
            if (StringUtils.isBlank(inviterUserId)) {
				inviterUserId = Optional.ofNullable(userInviteCodeMapperExt.selectByCode(requestDTO.getInviterMobileNo())).map(UserInviteCode::getUserId).orElse(null);
            }
        }
        Optional<InviteRegister> inviteRegisterOpt = Optional.ofNullable(inviterUserId)
                                                            .map(id -> {
                                                                InviteRegister inviteRegister = new InviteRegister();
                                                                inviteRegister.setUserId(accountMapping.getUserId());
                                                                inviteRegister.setInviterUserId(id);
                                                                inviteRegister.setCreateTime(new Date());
                                                                return inviteRegister;
                                                            });
        // 认证信息
        UserAuthorizationInfo authorizationInfo = EntityBuilder.buildLoginAccountAuthorizationInfo(accountMapping);
        boolean isSuccess = userLoginAccountLocalService.initAccountAndBasicInfo(accountMapping, account, basicInfo, extInfo, inviteRegisterOpt, authorizationInfo, score);
        if (isSuccess) {
            // 四周年活动用户邀请关系添加
            if(requestDTO.getFestivalFlag() != null && requestDTO.getFestivalFlag() && inviterUserId != null){
//                InviteUserInfoRequestDto inviteUserInfoRequestDto = new InviteUserInfoRequestDto();
//                inviteUserInfoRequestDto.setUserId(inviterUserId);
//                inviteUserInfoRequestDto.setInviteeUserId(accountMapping.getUserId());
//                inviteUserInfoRequestDto.setRegistDate(account.getCreateTime());
//                try {
//                    fyUserInfoDubboService.addUserRelation(inviteUserInfoRequestDto);
//                } catch (Exception e) {
//                    log.error("四周年活动用户邀请关系添加异常，入参:{}，e:{}", JSON.toJSONString(requestDTO), e);
//                }
            }
            // 清除当天注册短信发送次数缓存
            smsSender.removeDayTimesCache(UserSMSTypeEnum.REGISTER, requestDTO.getLoginMobileNo());
            // 清除当月注册短信发送次数缓存
            smsSender.removeMonthTimesCache(UserSMSTypeEnum.REGISTER, requestDTO.getLoginMobileNo());
            
            // 渠道引流
            try {
    			DraingeChannelUseAddReqDTO channelUseAddReqDTO = new DraingeChannelUseAddReqDTO();
    			channelUseAddReqDTO.setUserId(accountMapping.getUserId());
    			channelUseAddReqDTO.setLinkAddress(requestDTO.getRecommendUrl());
    			log.info("注册成功###用户引流###，推送添加消息内容:{}", JSON.toJSONString(channelUseAddReqDTO));
    			rabbitTemplate.convertAndSend(ActivityRabbitConstant.Exchange.ADD_DRAINGE_CHANNEL_USE_EXCHANGE, ActivityRabbitConstant.Key.ADD_DRAINGE_CHANNEL_USE_KEY, channelUseAddReqDTO);				
			} catch (Exception e) {
                log.error("注册成功###用户引流###推送添加信息异常,userId={}, errorMessage={}", accountMapping.getUserId(), e.getMessage());	
			}
            
            //新手任务 - 首次邀请好友 异步发送 发奖
            if(inviterUserId != null){
                try {
                    NoviceTaskRecordRequestDTO dto = new NoviceTaskRecordRequestDTO();
                    dto.setUserId(inviterUserId);
                    dto.setTaskType(NoviceTaskPrizeEnum.FRIST_INVITE_FRIEND_REGISTERED.getCode());
                    rabbitTemplate.convertAndSend(RabbitConstant.Exchange.NOVICE_TASK_RECORD, RabbitConstant.RoutingKey.NOVICE_TASK_RECORD, dto);
                } catch (Exception e) {
                    log.error("novice_task_activity首次邀请好友注册###调用新手任务###请求失败,userId={}, errorMessage={}", inviterUserId, e.getMessage());
                }
            }
            //新手注册外呼通知神盾
            try {
                boolean isH5Send = UserEnum.RegisterChannel.PLATFORM_H5.equals(requestDTO.getRegisterChannel()) && Objects.nonNull(requestDTO.getRecommendUrl());
                boolean inAppSend = Objects.nonNull(requestDTO.getIsInvest()) && requestDTO.getIsInvest() == true &&
                        (UserEnum.RegisterChannel.PLATFORM_APP_IOS.equals(requestDTO.getRegisterChannel())||
                                UserEnum.RegisterChannel.PLATFORM_APP_ANDROID.equals(requestDTO.getRegisterChannel()));
                String channelCode = "";
                if(isH5Send){
                    String linkAddress = requestDTO.getRecommendUrl();
                    String linkParams =linkAddress.substring(linkAddress.indexOf("?") + 1);
                    log.info("linkParams:{}",linkParams);
                    if(StringUtils.isNotEmpty(linkParams)) {
                        // 解析hannelCode和linkCode
                        Map<String, String> paramsMap = Splitter.on("&").splitToList(linkParams).stream()
                                .map(item -> Splitter.on("=").splitToList(item))
                                .collect(Collectors.toMap(item -> item.get(0), item -> item.get(1)));

                        // 设置channelCode和linkCode
                        channelCode = paramsMap.get("channelCode");
                    }
                }
                boolean isXinhualian = isH5Send && channelCode.equals(UserEnum.UserdrainageChannel.XINHUALIAN.getChannelCode());
                boolean isXinhualiandichan = isH5Send && channelCode.equals(UserEnum.UserdrainageChannel.XINHUALIANDICHAN.getChannelCode());
                log.info("用户userId:{}:{},{},{}",basicInfo.getUserId(),inAppSend,isXinhualian,isXinhualiandichan);
                if (inAppSend || isXinhualian || isXinhualiandichan) {
                    CallOutTaskAddReqDTO dto = new CallOutTaskAddReqDTO();
                    dto.setUserId(basicInfo.getUserId());
                    dto.setCallOutType((byte) 1);
                    dto.setRegisterChannel(basicInfo.getRegisterChannel());
                    dto.setChannelCode(inAppSend ? ChannelCodeEnum.APP.getChanelCode()
                            : (isXinhualian ? UserEnum.UserdrainageChannel.XINHUALIAN.getChannelCode() : UserEnum.UserdrainageChannel.XINHUALIANDICHAN.getChannelCode()));
                    dto.setRegisterTime(basicInfo.getCreateTime());
                    log.info("用户userId:{}新手外呼消息发送,createTime:{}", basicInfo.getUserId(),basicInfo.getCreateTime());
                    rabbitTemplate.convertAndSend(UserRabbitConstant.Exchange.CALL_OUT_TASK_ADD, UserRabbitConstant.RoutingKey.CALL_OUT_TASK_ADD, JSONObject.toJSONString(dto));
                }
            } catch (Exception e) {
                log.error("新手注册外呼通知神盾,userId={}, errorMessage={}", basicInfo.getUserId(), e.getMessage());
            }
            // 天秤数据回流
            CompletableFuture.runAsync(() -> {
                RegisterSuccessRequest registerSuccessRequest = new RegisterSuccessRequest();
                registerSuccessRequest.setUserId(String.valueOf(accountMapping.getUserId()));
                registerSuccessRequest.setUserNickName(basicInfo.getNickName());
                registerSuccessRequest.setUserAccount(basicInfo.getNiiwooCode());
                registerSuccessRequest.setAvatar(basicInfo.getHeadImage());
                registerSuccessRequest.setUserStatus(0);
                registerSuccessRequest.setUserName(requestDTO.getLoginMobileNo());
                registerSuccessRequest.setMobilePhone(requestDTO.getLoginMobileNo());
                registerSuccessRequest.setUserType(1);
                registerSuccessRequest.setRegisterTime(System.currentTimeMillis() * 1000L);
                registerSuccessRequest.setIpAddress(requestDTO.getIpAddress());
                registerSuccessRequest.setLongitude(requestDTO.getLongitude());
                registerSuccessRequest.setLatitude(requestDTO.getLatitude());
                registerSuccessRequest.setMapType(requestDTO.getMapType());
                registerSuccessRequest.setMacAddress(requestDTO.getMacAddress());
                registerSuccessRequest.setOperators(requestDTO.getOperators());
                if (!"unknown".equals(requestDTO.getWifiSSID())) {
                    registerSuccessRequest.setWifiSSID(requestDTO.getWifiSSID());
                }
                registerSuccessRequest.setDownChannel(requestDTO.getDownChannel());
                registerSuccessRequest.setAppVersion(requestDTO.getAppVersion());
                if (!"000".equals(requestDTO.getDeviceId())) {
                    registerSuccessRequest.setDeviceId(requestDTO.getDeviceId());
                }
                registerSuccessRequest.setSimMobilePhone(requestDTO.getSimMobilePhone());
                registerSuccessRequest.setOs(requestDTO.getOs());
                registerSuccessRequest.setOsVersion(requestDTO.getOs());
                registerSuccessRequest.setResolution(requestDTO.getResolution());
                registerSuccessRequest.setBrand(requestDTO.getBrand());
                registerSuccessRequest.setPhoneModel(requestDTO.getPhoneModel());
                registerSuccessRequest.setEquipmentStatus(requestDTO.getEquipmentStatus());
                registerSuccessRequest.setDualSim(requestDTO.getDualSim());
                registerSuccessRequest.setInviterUserId(inviteRegisterOpt.map(InviteRegister::getInviterUserId).orElse(null));
                ////用户来源(0-未知 1团贷网，2好帮贷，3你我金融，4房宝宝，5现金动车，6量化派 7 借钱快 8 融360 9卡牛)
                registerSuccessRequest.setFromType(TCFromTypeEnum.getTCFromTypeFromRegisterChannel(requestDTO.getRegisterChannel()));
                userDataBackFlowService.regiserSuccess(registerSuccessRequest);
            });

            //推荐人事件，发送MQ消息
            String finalInviterUserId = inviterUserId;
            CompletableFuture.runAsync(() -> {
                try {
                    Date currentDate = new Date();
                    RecommendEventReqDTO eventReqDTO = new RecommendEventReqDTO();
                    eventReqDTO.setRecommendUserId(finalInviterUserId);
                    eventReqDTO.setUserId(String.valueOf(accountMapping.getUserId()));
                    eventReqDTO.setRecommendDate(currentDate);
                    eventReqDTO.setUpdateDate(currentDate);
                    rabbitTemplate.convertAndSend(
                            BizEventRabbitConstant.Exchange.BIZ_EVENT_DIRECT_EXCHANGE,
                            BizEventRabbitConstant.Key.BIZ_EVENT_RECOMMEND_KEY,
                            eventReqDTO
                    );
                    log.info("【推荐人事件】消息发送成功，RecommendEventReqDTO:{}", JSON.toJSONString(eventReqDTO));
                } catch (Exception e) {
                    log.error("【推荐人事件】消息发送失败，userId:{}", accountMapping.getUserId(), e);
                }
            });

            //注册事件，发送MQ消息
            CompletableFuture.runAsync(() -> {
                try {
                    RegisterEventReqDTO eventReqDTO = new RegisterEventReqDTO();
                    eventReqDTO.setMobileNo(requestDTO.getLoginMobileNo());
                    eventReqDTO.setChannelSource(requestDTO.getDownChannel());
                    eventReqDTO.setRegisterDate(new Date());
                    if (StringUtils.isNotBlank(requestDTO.getLongitude())){
                        eventReqDTO.setLongitude(Double.parseDouble(requestDTO.getLongitude()));
                    }
                    if (StringUtils.isNotBlank(requestDTO.getLatitude())){
                        eventReqDTO.setLatitude(Double.parseDouble(requestDTO.getLatitude()));
                    }
                    eventReqDTO.setRecommendUserId(finalInviterUserId);
                    eventReqDTO.setRegisterAddress(extInfo.getRegisterAddress());
                    eventReqDTO.setAppVersion(requestDTO.getAppVersion());
                    eventReqDTO.setPhoneModel(requestDTO.getPhoneModel());
                    eventReqDTO.setUserId(String.valueOf(accountMapping.getUserId()));
                    eventReqDTO.setUpdateDate(new Date());
                    rabbitTemplate.convertAndSend(
                            BizEventRabbitConstant.Exchange.BIZ_EVENT_DIRECT_EXCHANGE,
                            BizEventRabbitConstant.Key.BIZ_EVENT_REGISTER_KEY,
                            eventReqDTO
                    );
                    log.info("【注册事件】消息发送成功，RegisterEventReqDTO:{}", JSON.toJSONString(eventReqDTO));
                } catch (Exception e) {
                    log.error("【注册事件】消息发送失败，userId:{}", accountMapping.getUserId(), e);
                }
            });

            // 个性化通知
            CompletableFuture.runAsync(() -> {
                try {
                	personalizedNotifyUserLocalService.pushRegisterSuccessMessageToUser(accountMapping.getUserId());
                    log.info("【个性化通知】消息发送成功，UserId:{}", accountMapping.getUserId());
                } catch (Exception e) {
                    log.error("【个性化通知】消息发送失败，userId:{}", accountMapping.getUserId(), e);
                }
            });
        }
        return accountMapping.getUserId();
    }

    /**
     * 保存拉取IM的用户你我号
     */
    private String updateUserInfoIM(UpdateUserInfoRequest request) {
        try {
            log.info("用户注册###IM获取你我号###request={}", JSON.toJSON(request));
            CompletableFuture<NiiwooNumberResponse> completableFuture = imService.updateUserInfo(request);
            NiiwooNumberResponse niiwooNumberResponse = completableFuture.get(5, TimeUnit.SECONDS);
            log.info("用户注册###IM获取你我号###response={}", JSON.toJSON(niiwooNumberResponse));
            //返回码code: 1失败，0成功
            if (niiwooNumberResponse.getCode() == 0) {
                return String.valueOf(niiwooNumberResponse.getImid());
            } else {
                log.error("用户注册###获取你我号###失败: userId={}", request.getGuid());
            }
        } catch (Exception e) {
            log.error(String.format("用户注册###获取你我号###异常: userId=%s, error=%s", request.getGuid(), e.getMessage()), e);
        }
        return "";
    }

    /**
     * 根据登录名获取登录账号
     */
    @Override
    public LoginAccountResponseDTO getLoginAccount(LoginAccountRequestDTO request) {
        if (StringUtils.isBlank(request.getLoginMobileNo())) {
            throw new BizException(LoginAccountErrorCode.MISS_LOGIN_NAME);
        }
        // 查找用户映射
        LoginAccountMapping accountMapping = Optional.ofNullable(userLoginAccountLocalService.getAccountMapping(getEncryptMobileNo(request.getLoginMobileNo())))
                                                     .orElseThrow(() -> new BizException(LoginAccountErrorCode.USERS_LOGIN_FAIL));
        // 查询用户行为限制 - 登录
        if (Optional.ofNullable(request.getIsCheckLoginForbid()).orElse(false)) {
            userForbidService.validUserForbidInfo(accountMapping.getUserId(), UserForbidTypeEnum.LOGIN);
        }
        // 查找用户账号
        UcAccount account = Optional.ofNullable(userLoginAccountLocalService.getAccountByUserId(accountMapping.getUserId()))
                                    .orElseThrow(() -> new BizException(LoginAccountErrorCode.USERS_LOGIN_FAIL));
        LoginAccountResponseDTO responseDTO = new LoginAccountResponseDTO();
        responseDTO.setUserId(account.getUserId());
        responseDTO.setLoginMobileNo(getDecryptMobileNo(account.getMobileNo()));
        responseDTO.setPassword(account.getPassword());
        responseDTO.setSlat(account.getSalt());
        return responseDTO;
    }

    /**
     * openId是否有绑定记录
     *
     * @param request
     * @return
     */
    @Override
    public ThirdLoginRequestDTO hasBindOpenId(ThirdLoginRequestDTO request) {
        AccountExtend accountExtend = accountExtendMapperExt.selectByOpenId(request.getOpenId(), request.getPlatformId());
        if(accountExtend != null) {
            request.setUserId(accountExtend.getUserId());
            if (accountExtend.getBindFlag().equals(BindFlagEnum.BINDFLAG.getCode())) {
                // 查询用户行为限制 - 登录
                userForbidService.validUserForbidInfo(accountExtend.getUserId(), UserForbidTypeEnum.LOGIN);
                request.setBindType(CheckThirdBindEnum.CAN_LOGIN.getCode());
                UcAccount ucAccount = userLoginAccountLocalService.getAccountByUserId(accountExtend.getUserId());
                if (ucAccount != null) {
                    request.setMobileNo(getDecryptMobileNo(ucAccount.getMobileNo()));
                }
            } else if (accountExtend.getBindFlag().equals(BindFlagEnum.UNBINDFLAG.getCode())) {
                request.setBindType(CheckThirdBindEnum.NEED_BIND.getCode());
            }
        }else {
            request.setBindType(CheckThirdBindEnum.NEED_REG.getCode());
        }

        return request;
    }

    /**
     * 根据openId获取帐号信息
     *
     * @param request
     * @return
     */
    @Override
    public LoginAccountResponseDTO getAccountInfoByOpenId(ThirdLoginRequestDTO request) {
        LoginAccountResponseDTO responseDTO = null;
        if (!HintManagerHolder.isMasterRouteOnly()) {
            HintManager.getInstance().setMasterRouteOnly();
        }
        AccountExtend accountExtend = accountExtendMapperExt.selectByOpenId(request.getOpenId(), request.getPlatformId());
        if (accountExtend != null && accountExtend.getBindFlag().equals(BindFlagEnum.BINDFLAG.getCode())) {
            // 查找用户账号
            if (!HintManagerHolder.isMasterRouteOnly()) {
                HintManager.getInstance().setMasterRouteOnly();
            }
            UcAccount account = userLoginAccountLocalService.getAccountByUserId(accountExtend.getUserId());
            responseDTO = new LoginAccountResponseDTO();
            responseDTO.setUserId(account.getUserId());
            responseDTO.setLoginMobileNo(getDecryptMobileNo(account.getMobileNo()));
            responseDTO.setPassword(request.getPlatformId().toString());
            responseDTO.setSlat(account.getSalt());
        }
        return responseDTO;
    }

    /**
     * 绑定第三方OpenId
     */
    @Override
    public boolean bindOpenId(ThirdLoginRequestDTO request) {
//        UserBasicInfo userBasicInfo = userBasicInfoMapperExt.getUserBaseInfoByMobileNo(privacyMasks.encryptPrivacy(request.getMobileNo()));
        AccountExtend accountExtend = accountExtendMapperExt.selectByOpenId(request.getOpenId(), request.getPlatformId());
        if (accountExtend != null) {
            accountExtend.setUpdateTime(new Date());
            accountExtend.setUserId(request.getUserId());
            accountExtend.setBindFlag(BindFlagEnum.BINDFLAG.getCode());
            accountExtend.setThirdNickName(request.getThirdNickName());
            accountExtend.setThirdHeadImage(request.getThirdHeadImage());
            accountExtend.setAppId(request.getAppId());
            int count = accountExtendMapperExt.updateByOpenId(accountExtend);
            if (count > 0) {
                return true;
            }
        } else {
            accountExtend = new AccountExtend();
            accountExtend.setId(snowflakeIdWorker.nextId());
            accountExtend.setUserId(request.getUserId());
            accountExtend.setOpenId(request.getOpenId());
            accountExtend.setPlatformId(request.getPlatformId());
            accountExtend.setBindFlag(BindFlagEnum.BINDFLAG.getCode());
            accountExtend.setThirdNickName(request.getThirdNickName());
            accountExtend.setThirdHeadImage(request.getThirdHeadImage());
            accountExtend.setUpdateTime(new Date());
            accountExtend.setCreateTime(new Date());
            accountExtend.setAppId(request.getAppId());
            int count = accountExtendMapperExt.insertSelective(accountExtend);
            if (count > 0) {
                sendNoviceTask(request);
                return true;
            }
        }
        return false;
    }

    private void sendNoviceTask(ThirdLoginRequestDTO request) {
        try {
            //你我金融的微信公众号如果匹配我们配置的
            if (request.getAppId() != null && wechatAccount.equals(request.getAppId())) {
                //绑定第三方公众号成功，发送MQ消息  -->用户是否新手任务
                NoviceTaskRecordRequestDTO dto = new NoviceTaskRecordRequestDTO();
                dto.setUserId(request.getUserId());
                dto.setTaskType(NoviceTaskPrizeEnum.FRIST_BIND_WECHAT.getCode());
                rabbitTemplate.convertAndSend(RabbitConstant.Exchange.NOVICE_TASK_RECORD, RabbitConstant.RoutingKey.NOVICE_TASK_RECORD, dto);
            }
        } catch (Exception e) {
            log.error("novice_task_activity用户昵称变更###调用否新手任务###请求失败,userId={}, errorMessage={}", request.getUserId(), e.getMessage());
        }
    }

    /**
     * 解绑第三方OpenId
     */
    @Override
    public boolean unbindOpenId(ThirdLoginRequestDTO request) {
        AccountExtend accountExtend = new AccountExtend();
        accountExtend.setBindFlag(BindFlagEnum.UNBINDFLAG.getCode());
        accountExtend.setOpenId(request.getOpenId());
        accountExtend.setPlatformId(request.getPlatformId());
        accountExtend.setUpdateTime(new Date());
        int updateCount = accountExtendMapperExt.updateByOpenId(accountExtend);
        if (updateCount > 0) {
            return true;
        }
        return false;
    }

    /**
     * 获取我的第三方平台绑定列表
     */
    @Override
    public List<ThirdLoginResponseDTO> getMyBindList(String userId) {
        List<ThirdLoginResponseDTO> responseDTOList = null;
        List<AccountExtend> accountExtendList = accountExtendMapperExt.selectByUserId(userId);
        if (accountExtendList != null && accountExtendList.size() > 0) {
            responseDTOList = new ArrayList<>();
            for (AccountExtend accountExtend : accountExtendList) {
                ThirdLoginResponseDTO responseDTO = new ThirdLoginResponseDTO();
                responseDTO.setOpenId(accountExtend.getOpenId());
                responseDTO.setPlatformId(accountExtend.getPlatformId());
                responseDTO.setThirdNickName(accountExtend.getThirdNickName());
                responseDTOList.add(responseDTO);
            }
        }
        return responseDTOList;
    }

    /**
     * 此接口废弃
     * @param userId
     * @param platformId
     * @return
     */
    @Override
    public boolean isExistsOtherOpenId(String userId, Byte platformId){
        // 查询用户行为限制 - 登录
        userForbidService.validUserForbidInfo(userId, UserForbidTypeEnum.LOGIN);
        return accountExtendMapperExt.isExistsOtherOpenId(userId, "",platformId) > 0;
    }

    @Override
    public boolean isExistsOtherOpenIdNew(String userId, String openId, Byte platformId){
        // 查询用户行为限制 - 登录
        userForbidService.validUserForbidInfo(userId, UserForbidTypeEnum.LOGIN);
        return accountExtendMapperExt.isExistsOtherOpenId(userId, openId,platformId) > 0;
    }

    /**
     * 登录前校验
     */
    @Override
    public void beforeLoginValid(BeforeLoginRequestDTO request) {
        if (StringUtils.isBlank(request.getLoginMobileNo())) {
            throw new BizException(LoginAccountErrorCode.MISS_LOGIN_NAME);
        }
        // 查询用户密码错误次数
        Optional<String> pwdErrorTimesOpt = userLoginAccountLocalService.getCacheValue(LOGIN_PASSWORD_ERROR_TIMES_FORMAT, new String[]{request.getLoginMobileNo()});
        int pwdErrorTimes = pwdErrorTimesOpt.map(Integer::valueOf).orElse(0);
        if (isOverMaxPasswordErrorTimes(pwdErrorTimes)) {
            throw new BizException(LoginAccountErrorCode.OVER_MAX_PASSWORD_ERROR_TIMES);
        }
        // 需要短信验证码但缺少验证码参数 | 登录验证码是否正确
        if (isNeedSMSCode(pwdErrorTimes) && !smsSender.isAuthCodeCacheRight(UserSMSTypeEnum.LOGIN, request.getLoginMobileNo(), request.getSmsCode())) {
            throw new BizException(LoginAccountErrorCode.SMS_CODE_ERROR);
        }
    }

    /**
     * 登录后处理
     */
    @Override
    public void postLoginHandle(PostLoginRequestDTO request) {
        if (StringUtils.isBlank(request.getLoginMobileNo())) {
            throw new BizException(LoginAccountErrorCode.MISS_LOGIN_NAME);
        }
        // 密码错误
        if (request.getIsPasswordError()) {
            getResponseWhenPasswordError(request.getLoginMobileNo());
        } else {
            // 登录成功
            UcAccount account = userLoginAccountLocalService.getAccountByUserId(request.getUserId());
            if (account != null) {
                UserExtInfo oldExtInfo = userLoginAccountLocalService.getAccountExtInfo(request.getUserId());
                // 更新登录信息
                UserExtInfo extInfo = new UserExtInfo();
                extInfo.setUserId(account.getUserId());
                extInfo.setDeviceType(request.getDeviceType() != null ? request.getDeviceType().getValue() : RegisterDeviceType.WEB.getValue()); //默认2-web-网页
                extInfo.setLastLoginProvince(request.getProvinceName());
                extInfo.setLastLoginCity(request.getCityName());
                extInfo.setLastLoginArea(request.getAreaName());
                extInfo.setLastLoginIp(request.getClientAccessIP());
                extInfo.setLastLoginLongitude(request.getLongitude());
                extInfo.setLastLoginLatitude(request.getLatitude());
                extInfo.setLastLoginAddress(request.getAddress());
                UserEnum.RegisterDeviceType deviceTypeEnum = request.getDeviceType();
                if(deviceTypeEnum != null) {
                	/**第三方或WEB方式并不是第一次登录,不更新最后登录设备和极光ID*/
                	if(UserEnum.RegisterDeviceType.IOS.equals(deviceTypeEnum) || UserEnum.RegisterDeviceType.ANDROID.equals(deviceTypeEnum) || oldExtInfo.getLastLoginDevice() == null) {
                		extInfo.setJiGuangPushId(request.getJiGuangPushId());
                		extInfo.setLastLoginDevice(request.getDeviceType().getValue());
                	}
                }
                extInfo.setUpdateTime(new Date());
                extInfo.setBlackBox(request.getBlackBox());
                userLoginAccountLocalService.updateLoginInfo(extInfo);
                //  清除密码错误次数
                userLoginAccountLocalService.delCacheValue(LOGIN_PASSWORD_ERROR_TIMES_FORMAT, new String[]{request.getLoginMobileNo()});
                // 天秤数据回流
                CompletableFuture.runAsync(() -> {
                    LoginSuccessRequest loginSuccessRequest = new LoginSuccessRequest();
                    loginSuccessRequest.setUserId(String.valueOf(account.getUserId()));
                    loginSuccessRequest.setMobilePhone(privacyMasks.decryptPrivacy(account.getMobileNo()));
                    loginSuccessRequest.setUserName(loginSuccessRequest.getMobilePhone());
                    loginSuccessRequest.setLoginTime(Instant.now().toEpochMilli() * 1000L);
                    loginSuccessRequest.setIpAddress(request.getClientAccessIP());
                    loginSuccessRequest.setLongitude(request.getLongitude());
                    loginSuccessRequest.setLatitude(request.getLatitude());
                    loginSuccessRequest.setMapType(request.getMapType());
                    loginSuccessRequest.setMacAddress(request.getMacAddress());
                    if (!"unknown".equals(request.getWifiSSID())) {
                        loginSuccessRequest.setWifiSSID(request.getWifiSSID());
                    }
                    loginSuccessRequest.setDownChannel(request.getDownChannel());
                    loginSuccessRequest.setAppVersion(request.getAppVersion());
                    if (!"000".equals(request.getDeviceId())) {
                        loginSuccessRequest.setDeviceId(request.getDeviceId());
                    }
                    loginSuccessRequest.setSimMobilePhone(request.getSimMobilePhone());
                    loginSuccessRequest.setOs(request.getOs());
                    loginSuccessRequest.setOsVersion(request.getOsVersion());
                    loginSuccessRequest.setResolution(request.getResolution());
                    loginSuccessRequest.setPhoneModel(request.getPhoneModel());
                    loginSuccessRequest.setBrand(request.getBrand());
                    loginSuccessRequest.setEquipmentStatus(request.getEquipmentStatus());
                    loginSuccessRequest.setDualSim(request.getDualSim());
                    userDataBackFlowService.loginSuccess(loginSuccessRequest);
                });
                // 如果第一次的登录， 则APP需要更新系统版本和渠道ID
                boolean isFirstLogin = oldExtInfo == null || oldExtInfo.getLastLoginDevice() == null;
                boolean isUpdateLoginInfoExists = StringUtils.isNotBlank(request.getOs()) || StringUtils.isNotBlank(request.getDownChannel());
                if (isFirstLogin && isUpdateLoginInfoExists) {
                	try {
						DraingeChannelUseAddReqDTO channelUseAddReqDTO = new DraingeChannelUseAddReqDTO();
						channelUseAddReqDTO.setUserId(account.getUserId());
						OsTyprEnum osTypr = Optional.ofNullable(request.getOs()).filter(StringUtils::isNotBlank).map(os -> {
							if (os.equalsIgnoreCase("IOS")) {
								return OsTyprEnum.IOS;
							} else if (os.equalsIgnoreCase("Android")) {
								return OsTyprEnum.Android;
							} else {
								return OsTyprEnum.UNkonw;
							}
						}).orElse(OsTyprEnum.UNkonw);
						channelUseAddReqDTO.setOsTyprId(osTypr);
						channelUseAddReqDTO.setAppChannelId(request.getDownChannel());
		    			log.info("注册成功###用户引流###推送更新消息内容:{}", JSON.toJSONString(channelUseAddReqDTO));
		    			rabbitTemplate.convertAndSend(ActivityRabbitConstant.Exchange.ADD_DRAINGE_CHANNEL_USE_EXCHANGE, ActivityRabbitConstant.Key.EDIT_DRAINGE_CHANNEL_USE_KEY, channelUseAddReqDTO);
                	} catch (Exception e) {
                		log.error("注册成功###用户引流###推送更新消息异常,userId={}, errorMessage={}", account.getUserId(), e.getMessage());
					}
                }
            }

        }
    }

    /**
     * 当密码错误，使用异常返回响应
     * @param loginMobileNo 登录手机号
     */
    private void getResponseWhenPasswordError(String loginMobileNo) {
        int times = incrPasswordErrorTimes(loginMobileNo);
        // 超过最大值，设置锁定时间，默认24 hours
        if (isOverMaxPasswordErrorTimes(times)) {
            int duration = getSysConfParamDto(PASSWORD_ERROR_LOCK_DURATION).map(dto -> Integer.valueOf(dto.getParamValue())).orElse(24);
            userLoginAccountLocalService.expireCacheValue(LOGIN_PASSWORD_ERROR_TIMES_FORMAT, new String[]{loginMobileNo}, duration, TimeUnit.HOURS);
            throw new BizException(LoginAccountErrorCode.OVER_MAX_PASSWORD_ERROR_TIMES);
            // 剩余最后一次登录机会
        } else if (times == 4) {
            throw new BizException(LoginAccountErrorCode.LAST_LOGIN_TIMES);
            // 是否需要密码
        } else if (isNeedSMSCode(times)) {
            throw new BizException(LoginAccountErrorCode.PASSWORD_ERROR_AND_NEED_SMS_CODE);
            // 否则密码错误
        } else {
            throw new BizException(LoginAccountErrorCode.PASSWORD_ERROR);
        }
    }

    /**
     * 重置登录密码
     */
    @Override
    public boolean resetLoginPasswordBySMS(ResetLoginPasswordRequestDTO requestDTO) {
        // 验证码
        if (!smsSender.isAuthCodeCacheRight(UserSMSTypeEnum.RESET_LOGIN_PASSWORD, requestDTO.getLoginMobileNo(), requestDTO.getSmsCode())) {
            throw new BizException(LoginAccountErrorCode.SMS_CODE_ERROR);
        }
        String encryptMobileNo = getEncryptMobileNo(requestDTO.getLoginMobileNo());
        // 查找用户映射
        LoginAccountMapping accountMapping = userLoginAccountLocalService.getAccountMapping(encryptMobileNo);
        if (accountMapping == null) {
            throw new BizException(LoginAccountErrorCode.USERS_NOT_EXIST);
        }
        // 查找用户账号
        UcAccount account = userLoginAccountLocalService.getAccountByUserId(accountMapping.getUserId());
        if (account == null) {
            throw new BizException(LoginAccountErrorCode.USERS_NOT_EXIST);
        }
        UcAccount updateAccount = new UcAccount();
        updateAccount.setUserId(account.getUserId());
        updateAccount.setSalt(requestDTO.getSalt());
        updateAccount.setPassword(requestDTO.getPassword());
        boolean isSuccess = userLoginAccountLocalService.updateLoginAccountInfo(updateAccount);
        if (isSuccess) {
            // 修改成功，清除密码错误次数
            userLoginAccountLocalService.delCacheValue(LOGIN_PASSWORD_ERROR_TIMES_FORMAT, new String[]{requestDTO.getLoginMobileNo()});
        }
        return isSuccess;
    }

    @Override
    public boolean getLoginSMSStatus(LoginAccountRequestDTO request) {
        int times = userLoginAccountLocalService.getCacheValue(LOGIN_PASSWORD_ERROR_TIMES_FORMAT, new String[]{request.getLoginMobileNo()}).map(Integer::valueOf).orElse(0);
        if (isOverMaxPasswordErrorTimes(times)) {
            throw new BizException(LoginAccountErrorCode.OVER_MAX_PASSWORD_ERROR_TIMES);
        }
        if (isNeedSMSCode(times)) {
            throw new BizException(LoginAccountErrorCode.PASSWORD_ERROR_AND_NEED_SMS_CODE);
        }
        // 机构用户第一次登陆重置密码判断
        UserBasicInfo userBasicInfo = userBasicInfoMapperExt.getUserBaseInfoByMobileNo(privacyMasks.encryptPrivacy(request.getLoginMobileNo()));
        if(userBasicInfo != null && !UserEnum.RegisterChannel.isPlatformChannel(userBasicInfo.getRegisterChannel())) {
            UserExtInfo userExtInfo = userExtInfoMapper.selectByPrimaryKey(userBasicInfo.getUserId());
            if(userExtInfo == null || userExtInfo.getLastLoginDevice() == null){
                throw new BizException(LoginAccountErrorCode.ORG_USER_FIRST_LOGIN_RESET_PASSWORD);
            }
        }
        return true;
    }

    /**
     * 增加密码错误次数
     *
     * @param loginMobileNo 登录名
     */
    private int incrPasswordErrorTimes(String loginMobileNo) {
        return userLoginAccountLocalService.incrCacheValue(LOGIN_PASSWORD_ERROR_TIMES_FORMAT, new String[]{loginMobileNo}, getLeftSecondsToday(), TimeUnit.SECONDS).orElse(0L).intValue();
    }

    /**
     * 获取当天剩余秒数
     */
    private long getLeftSecondsToday() {
        LocalDate now = new LocalDate();
        return new Duration(now.toDateTimeAtCurrentTime(), now.plusDays(1).toDateTimeAtStartOfDay()).getStandardSeconds();
    }

    /**
     * 是否超过密码错误最大阈值
     */
    private boolean isOverMaxPasswordErrorTimes(int currentErrorTimes) {
        return currentErrorTimes >= getSysConfParamDto(MAX_PASSWORD_ERROR_TIMES).map(dto -> Integer.valueOf(dto.getParamValue())).orElse(5);
    }

    /**
     * 是否需要短信验证码
     */
    private boolean isNeedSMSCode(int currentErrorTimes) {
        return currentErrorTimes >= getSysConfParamDto(NEED_SMS_PASSWORD_ERROR_TIMES).map(dto -> Integer.valueOf(dto.getParamValue())).orElse(3);
    }

    /**
     * 加密手机号
     *
     * @param mobileNo 手机号
     */
    private String getEncryptMobileNo(String mobileNo) {
        return privacyMasks.encryptPrivacy(mobileNo);
    }

    /**
     * 解密手机号
     *
     * @param mobileNo 手机号
     */
    private String getDecryptMobileNo(String mobileNo) {
        return privacyMasks.decryptPrivacy(mobileNo);
    }

    /**
     * 随机生成昵称
     *
     * @return 昵称
     */
    private String generateNiiwooNickname() {
        return "niiwoo" + StringHelper.genRandomStr(10);
    }

    /**
     * 随机获取一张系统头像作为默认头像
     *
     * @return 头像URL
     */
    private String randomGetSystemHeader() {
        return "";
    }

    @Override
    public SysParamService getSysParamService() {
        return sysParamService;
    }

    /**
     * 加密身份证号码
     *
     * @param idCard 身份证号码明文
     */
    private String ecryptIdCard(String idCard) {
        return privacyMasks.encryptPrivacy(idCard);
    }

    /**
     * rong360注册
     *
     * @param registerRequest
     * @param encryptMobileNo
     * @return
     */
    private String autoRegist(AutoRegisterAndIdentityDto registerRequest, String encryptMobileNo) {
        // 初始化用户相关信息并保存
        Date now = new Date();
        String userId = UUID.randomUUID().toString();
        // 账号映射
        LoginAccountMapping accountMapping = new LoginAccountMapping();
        accountMapping.setAccountName(encryptMobileNo);
        accountMapping.setUserId(userId);
        // 账号
        UcAccount account = new UcAccount();
        account.setUserId(userId);
        account.setMobileNo(encryptMobileNo);
        account.setSalt(registerRequest.getSalt());
        account.setPassword(registerRequest.getPassword());
        account.setCreateTime(now);
        // 基础信息
        UserBasicInfo basicInfo = new UserBasicInfo();
        basicInfo.setUserId(userId);
        basicInfo.setMobileNo(encryptMobileNo);
        basicInfo.setRegisterChannel(registerRequest.getRegisterChannel().getValue());
        basicInfo.setNiiwooScore(300); //初始化用户你我分为300
        final String nickName = generateNiiwooNickname();
        basicInfo.setNickName(nickName);
        basicInfo.setHeadImage(randomGetSystemHeader());
        basicInfo.setGender((byte)UserEnum.Gender.UNKNOWN.getValue());
        basicInfo.setPersonalSign("");
        basicInfo.setCreateTime(now);
        basicInfo.setIdentityTag(UserEnum.IdentityTag.NO_IDENTITY.getType());
        //注册拉取你我号
        UpdateUserInfoRequest request = new UpdateUserInfoRequest();
        request.setGuid(userId);
        request.setNickname(nickName);
        request.setMobile(registerRequest.getLoginMobileNo());
        request.setAvatar(randomGetSystemHeader());
        request.setGender((byte)UserEnum.Gender.UNKNOWN.getValue());
        request.setPassword(registerRequest.getPassword());
        basicInfo.setNiiwooCode(updateUserInfoIM(request));
        // 扩展信息(融360用户未在app直接注册，无其他信息)
        UserExtInfo extInfo = new UserExtInfo();
        extInfo.setUserId(userId);
        extInfo.setCreateTime(new Date());
        // 认证信息
        UserAuthorizationInfo authorizationInfo = new UserAuthorizationInfo();
        authorizationInfo.setUserId(userId);
        authorizationInfo.setZhimaScore(registerRequest.getZhiMa());
        authorizationInfo.setZhimaFailureReason("");
        authorizationInfo.setSocialSecurityAuthCity(registerRequest.getInsureCity());
        authorizationInfo.setFadadaCacertId("");
        authorizationInfo.setCreateTime(now);
        //你我分
        NiiwooScore score = new NiiwooScore();
        score.setId(snowflakeIdWorker.nextId());
        score.setUserId(userId);
        score.setScore(300);
        score.setScoreDetail("{'EngagementAbility':'0','CreditHistory':'0','GuanXi':'0','Behavior':'0','IdFeature':'0'}");
        score.setEvaluateTime(new Date());
        score.setCreateTime(new Date());
        score.setEvaluateTime(new Date());
        boolean isSuccess = userLoginAccountLocalService.initAccountAndBasicInfo(accountMapping, account, basicInfo,authorizationInfo,score,extInfo);
        if (isSuccess) {
            // 天秤数据回流
            RegisterSuccessRequest registerSuccessRequest = new RegisterSuccessRequest();
            registerSuccessRequest.setUserId(String.valueOf(userId));
            registerSuccessRequest.setUserNickName(basicInfo.getNickName());
            registerSuccessRequest.setUserAccount(basicInfo.getNiiwooCode());
            registerSuccessRequest.setAvatar(basicInfo.getHeadImage());
            registerSuccessRequest.setUserName(registerRequest.getLoginMobileNo());
            registerSuccessRequest.setMobilePhone(registerRequest.getLoginMobileNo());
            ////用户来源(0-未知 1团贷网，2好帮贷，3你我金融，4房宝宝，5现金动车，6量化派 7 借钱快 8 融360 9卡牛)
            registerSuccessRequest.setFromType(TCFromTypeEnum.getTCFromTypeFromRegisterChannel(registerRequest.getRegisterChannel()));
            registerSuccessRequest.setRegisterTime(System.currentTimeMillis() * 1000L);
            userDataBackFlowService.regiserSuccess(registerSuccessRequest);
        }
        return isSuccess ? userId : String.valueOf(UserAutoRegisterDto.FAIL_RET);
    }

    /**
     * 鹏元二要素认证
     * @param realName
     * @param idCard
     * @return
     */
    private boolean verifyIdNameByPengYuan(String realName, String idCard) {
        VerNameRequset req = new VerNameRequset();

        req.setRealName(realName);
        req.setIdentityCard(idCard);
        req.setFunctionCode(FunctionCodeEnum.QUERY_VERIFY_ID_NAME.getBodyFunctionCode());
        req.setTransDate(new Date());
        req.setTransNo(String.valueOf(System.currentTimeMillis()));

        VerNameResponse resp = null;
        try {
            CompletableFuture<VerNameResponse> future = tianchengVerNameService.tianchengVerName(req);
            resp = future.get(5L, TimeUnit.SECONDS);
            log.info("天秤鹏元二要素验证，request:{}, response:{}", JSON.toJSONString(req), JSON.toJSONString(resp));

            if (resp == null) {
                log.error("天秤鹏元二要素验证失败：无结果，request:{}, response:{}", JSON.toJSONString(req), JSON.toJSONString(resp));
                return false;
            } else if (VerNameResponse.TianChengStatusEnum.TIAN_CHENG_STATUS_TRUE.getCode().equals(resp.getTianChengStatus())
                    && VerNameResponse.Status.STATUS_TRUE.getCode().equals(resp.getStatus())
                    && VerNameResponse.CheckResult.CHECK_RESULT_TRUE.getCode().equals(resp.getCheckResult())) {
                log.error("天秤鹏元二要素验证通过，request:{}", JSON.toJSONString(req));
                return true;
            } else {
                log.error("天秤鹏元二要素验证失败：不通过，request:{}, response:{}", JSON.toJSONString(req), JSON.toJSONString(resp));
                return false;
            }
        } catch (Exception e) {
            log.error("天秤鹏元二要素验证失败：请求异常，request:{}, response:{}", JSON.toJSONString(req), JSON.toJSONString(resp), e);
            return false;
        }
    }

    /**
     * 二要素验证
     *
     * @param registerRequest
     * @param result
     * @return
     */
    private boolean verifyIdName(AutoRegisterAndIdentityDto registerRequest, UserAutoRegisterDto result) {
        KaoLaVerNameRequset req = new KaoLaVerNameRequset();

        req.setRealName(registerRequest.getName());
        req.setIdentityCard(registerRequest.getIdCardNo());
        req.setFunctionCode(FunctionCodeEnum.KAOLA_QUERY_VERIFY_ID_NAME.getBodyFunctionCode());
        req.setIsNew("0");
        req.setTransDate(new Date());
        req.setTransNo(String.valueOf(System.currentTimeMillis()));

        KaoLaVerNameResponse resp = null;
        try {
            CompletableFuture<KaoLaVerNameResponse> future = tianchengVerNameService.tianchengKaoLaVerName(req);
            resp = future.get(5L, TimeUnit.SECONDS);
            log.info("天秤二要素验证，request:{}, response:{}", JSON.toJSONString(req), JSON.toJSONString(resp));

            if (resp == null) {
                result.setRet(UserAutoRegisterDto.FAIL_RET);
                result.setMessage("接口返回无结果");
                return true;
            } else if (KaoLaVerNameResponse.TianChengStatusEnum.SUCCESS.getCode().equals(resp.getTianChengStatus())
                    && KaoLaVerNameResponse.ResultEnum.VALID.getCode().equals(resp.getResult())) {
                return false;
            } else {
                result.setRet(UserAutoRegisterDto.FAIL_RET);
                result.setMessage("实名认证不通过");
                return true;
            }
        } catch (Exception e) {
            log.error("天秤二要素验证出错，request:{}, response:{}", JSON.toJSONString(req), JSON.toJSONString(resp), e);
            result.setRet(UserAutoRegisterDto.FAIL_RET);
            result.setMessage("实名认证异常");
            return true;
        }
    }

    @Override
    public UserSecurityPasswordResponseDTO queryUserSecurityPassword(String userId) {
        UserSecurityPasswordResponseDTO responseDTO = new UserSecurityPasswordResponseDTO();
        UcAccount ucAccount = userLoginAccountLocalService.getAccountByUserId(userId);
        if (ucAccount == null)
            return null;
        if (ucAccount.getPassword() == null) {
            responseDTO.setGesturePassword(LoginPasswordEnum.IS_NOT_SET.getStatus());
        } else {
            responseDTO.setLoginPassword(LoginPasswordEnum.HAS_BEEN_SET.getStatus());
        }
        return responseDTO;
    }

    @Override
    public void saveJiGuangPushId(String userId, String jiGuangPushId) {
        UserExtInfo extInfo = new UserExtInfo();
        extInfo.setUserId(userId);
        extInfo.setJiGuangPushId(jiGuangPushId);
        userLoginAccountLocalService.updateLoginInfo(extInfo);
    }

    @Override
    public boolean unlockAccount(String mobileNo, String smsCode) {
        int times = userLoginAccountLocalService.getCacheValue(LOGIN_PASSWORD_ERROR_TIMES_FORMAT, new String[]{mobileNo}).map(Integer::valueOf).orElse(0);
        if (!isOverMaxPasswordErrorTimes(times)) {
            return true;
        }
        if (!smsSender.isAuthCodeCacheRight(UserSMSTypeEnum.UNLOCK_ACCOUNT, mobileNo, smsCode)) {
            throw new BizException(LoginAccountErrorCode.SMS_CODE_ERROR);
        }
        userLoginAccountLocalService.delCacheValue(LOGIN_PASSWORD_ERROR_TIMES_FORMAT, new String[]{mobileNo});
        return true;
    }

    /**
     * 资产端用户自动注册
     *
     * @param assetAutoRegisterBaseReqDTO
     * @return
     */
    @Override
    public AssetAutoRegisterRespDTO assetAutoRegister(AssetAutoRegisterBaseReqDTO assetAutoRegisterBaseReqDTO) {
        log.info("用户自动注册,手机号码={},注册渠道={},请求参数={}", assetAutoRegisterBaseReqDTO.getRegisterMobile(),assetAutoRegisterBaseReqDTO.getRegisterChannel()==null?null:assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc(),JSONObject.toJSONString(assetAutoRegisterBaseReqDTO));
        AssetAutoRegisterRespDTO registerRespDTO = new AssetAutoRegisterRespDTO(AssetAutoRegisterRespDTO.AssetAutoRegisterRespEnum.FAILURE);
        if(Objects.isNull(assetAutoRegisterBaseReqDTO.getRegisterChannel())
                || !Arrays.asList(UserEnum.RegisterChannel.values()).contains(assetAutoRegisterBaseReqDTO.getRegisterChannel())){
            log.error("用户自动注册,手机号码={},注册渠道={},注册失败,原因是注册来源为空或你我金融未接入该资产端.", assetAutoRegisterBaseReqDTO.getRegisterMobile(),assetAutoRegisterBaseReqDTO.getRegisterChannel()==null?null:assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc());
            registerRespDTO.setRegisterRespEnum(AssetAutoRegisterRespDTO.AssetAutoRegisterRespEnum.REGISTER_CHANNEL_ERROR);
            return registerRespDTO;
        }

        final String encryptMobileNo = getEncryptMobileNo(assetAutoRegisterBaseReqDTO.getRegisterMobile());
        final String encryptIdCard = ecryptIdCard(assetAutoRegisterBaseReqDTO.getIdCard());

        //校验用户手机号码是否在你我金融注册
        LoginAccountMapping loginAccountMapping = userLoginAccountLocalService.getAccountMapping(encryptMobileNo);

        //用户身份信息映射
        boolean identityMappingExist = identityMappingService.isExists(encryptIdCard);

        //手机号码已在你我金融注册
        if(Objects.nonNull(loginAccountMapping)){
            log.info("用户自动注册,手机号码={},注册渠道={},用户手机号码在你我金融已注册.", assetAutoRegisterBaseReqDTO.getRegisterMobile(),assetAutoRegisterBaseReqDTO.getRegisterChannel()==null?null:assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc());
            //校验用户二要素信息是否在你我金融存在
            DataStatus dataStatus = userStatusService.getByUserIdAndType(loginAccountMapping.getUserId(), UserDataTypeEnum.TWO_ELEMENT);//t_uc_data_status表二要素认证是否写入
            IdentityInfo identityInfo = userIdentityService.getByUserId(loginAccountMapping.getUserId());//t_uc_identity_info表用户身份证信息是否写入


            //用户二要素信息存在你我金融(二要素认证信息,身份证信息)
            if (Objects.nonNull(dataStatus) && Objects.nonNull(identityInfo)){
                //用户信息二要素存在,校验用户二要素认证状态
                if(dataStatus.getDataStatus().equals(UserDataStatusEnum.RealNameAuthStatus.PASS_CERTIFIED.getStatus())){
                    //二要素认证状态通过,比对资产端用户二要素信息和你我金融二要素信息
                    if(encryptIdCard.equals(identityInfo.getIdCard())
                            && assetAutoRegisterBaseReqDTO.getRealName().equals(identityInfo.getName())){//身份信息-身份证号码和姓名一致
                        log.info("用户自动注册,手机号码={},注册渠道={},用户手机号码在你我金融已注册,且用户二要素信息和你我金融已认证的二要素信息一致.", assetAutoRegisterBaseReqDTO.getRegisterMobile(),assetAutoRegisterBaseReqDTO.getRegisterChannel()==null?null:assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc());
                        registerRespDTO.setRegisterRespEnum(AssetAutoRegisterRespDTO.AssetAutoRegisterRespEnum.SUCCESS);
                        registerRespDTO.setUserId(loginAccountMapping.getUserId());
                        return registerRespDTO;
                    }else{
                        log.error("用户自动注册,手机号码={},注册渠道={},用户手机号码在你我金融已注册,且二要素信息已保存,二要素信息已认证,但资产端推送的身份证与你我金融平台已存在的身份证不一致,用户ID={}.", assetAutoRegisterBaseReqDTO.getRegisterMobile(),assetAutoRegisterBaseReqDTO.getRegisterChannel()==null?null:assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc(),identityInfo.getUserId());
                        registerRespDTO.setRegisterRespEnum(AssetAutoRegisterRespDTO.AssetAutoRegisterRespEnum.USER_IDENTITY_INFO_IS_NOT_MATCH_NIIWOO);
                        return registerRespDTO;
                    }


                }else{
                    //用户二要素信息已存在,但二要素认证状态未通过,请求天称验证资产端推送的用户二要素信息
                    if (!verifyIdNameByPengYuan(assetAutoRegisterBaseReqDTO.getRealName(), assetAutoRegisterBaseReqDTO.getIdCard())) {
                        log.error("用户自动注册,手机号码={},注册渠道={},天称实名认证用户二要素(姓名+身份证)信息不匹配,用户加密身份证号码={},用户真实姓名={}.", assetAutoRegisterBaseReqDTO.getRegisterMobile(),assetAutoRegisterBaseReqDTO.getRegisterChannel()==null?null:assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc());
                        registerRespDTO.setRegisterRespEnum(AssetAutoRegisterRespDTO.AssetAutoRegisterRespEnum.USER_IDENTITY_INFO_CHAOS);
                        return registerRespDTO;
                    }

                    //天称实名认证通过,更新用户二要素信息
                    log.info("用户自动注册,手机号码={},注册渠道={},用户已在你我金融注册,保存的用户二要素信息未通过认证时,且资产端推送的二要素信息通过认证,使用资产端二要素信息更新你我金融保存的二要素信息,用户ID={},你我金融二要素信息:[姓名={},身份证={}],资产端推送二要素信息:[姓名={},身份证={}].", assetAutoRegisterBaseReqDTO.getRegisterMobile(), assetAutoRegisterBaseReqDTO.getRegisterChannel() == null ? null : assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc(), loginAccountMapping.getUserId(), identityInfo.getName(), privacyMasks.decryptPrivacy(identityInfo.getIdCard()),
                            assetAutoRegisterBaseReqDTO.getRealName(),assetAutoRegisterBaseReqDTO.getIdCard());
                    return updateAuthInfo(assetAutoRegisterBaseReqDTO, registerRespDTO, encryptIdCard, loginAccountMapping.getUserId());
                }
            }

            //用户二要素信息不存在你我金融(二要素认证,身份证信息,身份映射信息均不存在,或者用户的二要素信息相关表数据不完整):资产端推送用户已在你我金融注册,但是未实名
            else{
                if(identityMappingExist){
                    log.error("用户自动注册,手机号码={},注册渠道={},用户已在你我金融注册,但用户身份证已被使用,身份证号={}", assetAutoRegisterBaseReqDTO.getRegisterMobile(), assetAutoRegisterBaseReqDTO.getRegisterChannel() == null ? null : assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc(),assetAutoRegisterBaseReqDTO.getIdCard());
                    registerRespDTO.setRegisterRespEnum(AssetAutoRegisterRespDTO.AssetAutoRegisterRespEnum.USER_IDENTITY_INFO_EXIST);
                    return registerRespDTO;
                }

                //请求天称实名认证验证资产端推送的用户二要素信息
                if (!verifyIdNameByPengYuan(assetAutoRegisterBaseReqDTO.getRealName(), assetAutoRegisterBaseReqDTO.getIdCard())) {
                    log.error("用户自动注册,手机号码={},注册渠道={},用户已在你我金融注册,但未实名认证,现通过天称实名认证用户二要素(姓名+身份证)信息不匹配,身份证号={},真实姓名={}.",
                            assetAutoRegisterBaseReqDTO.getRegisterMobile(), assetAutoRegisterBaseReqDTO.getRegisterChannel() == null ? null : assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc(), assetAutoRegisterBaseReqDTO.getIdCard(),assetAutoRegisterBaseReqDTO.getRealName());
                    registerRespDTO.setRegisterRespEnum(AssetAutoRegisterRespDTO.AssetAutoRegisterRespEnum.USER_IDENTITY_INFO_CHAOS);
                    return registerRespDTO;
                }

                //face++验证通过,更新用户二要素信息
                return updateAuthInfo(assetAutoRegisterBaseReqDTO, registerRespDTO, encryptIdCard, loginAccountMapping.getUserId());

            }
        }
        //用户手机号码未在你我金融注册
        else{
            log.info("用户自动注册,手机号码={},注册渠道={},用户手机号码未在你我金融未注册.", assetAutoRegisterBaseReqDTO.getRegisterMobile(), assetAutoRegisterBaseReqDTO.getRegisterChannel() == null ? null : assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc());
            //用户身份映射信息均不存在,则资产端推送用户为新用户
            if(!identityMappingExist){
                //请求face++验证资产端推送的用户二要素信息
                if (!verifyIdNameByPengYuan(assetAutoRegisterBaseReqDTO.getRealName(), assetAutoRegisterBaseReqDTO.getIdCard())) {
                    log.error("用户自动注册,手机号码={},注册渠道={},用户手机号码未在你我金融未注册,天称实名认证用户二要素(姓名+身份证)信息不匹配,身份证号={},真实姓名={}", assetAutoRegisterBaseReqDTO.getRegisterMobile(), assetAutoRegisterBaseReqDTO.getRegisterChannel() == null ? null : assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc(),assetAutoRegisterBaseReqDTO.getIdCard(), assetAutoRegisterBaseReqDTO.getRealName());
                    registerRespDTO.setRegisterRespEnum(AssetAutoRegisterRespDTO.AssetAutoRegisterRespEnum.USER_IDENTITY_INFO_CHAOS);
                    return registerRespDTO;
                }

                //天称实名认证通过,自动注册该用户
                String userId = doAutoRegistr(assetAutoRegisterBaseReqDTO, encryptMobileNo);
                if(Objects.isNull(userId)){
                    log.error("用户自动注册,手机号码={},注册渠道={},用户手机号码未在你我金融未注册,天称实名认证通过后保存用户信息失败.", assetAutoRegisterBaseReqDTO.getRegisterMobile(), assetAutoRegisterBaseReqDTO.getRegisterChannel() == null ? null : assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc());
                    registerRespDTO.setRegisterRespEnum(AssetAutoRegisterRespDTO.AssetAutoRegisterRespEnum.FAILURE);
                    return registerRespDTO;
                }

                //注册成功,写入用户二要素信息到你我金融
                return updateAuthInfo(assetAutoRegisterBaseReqDTO, registerRespDTO, encryptIdCard, userId);
            }

            /*
             * 用户在你我金融允许用多个手机号进行注册,但是实名信息只会关联一个手机号码.
             * 资产端进行自动注册时,若手机号码未注册,则需要验证实名信息是否已存在,如存在,则予以拒绝.举例:
             * 用户在你我金融用A手机号码注册并实名,在资产端用B手机号进行自动注册,应该予以拒绝
             */
            log.error("用户自动注册,手机号码={},注册渠道={},用户手机号码未在你我金融未注册,但用户身份证已被使用,身份证号={}", assetAutoRegisterBaseReqDTO.getRegisterMobile(), assetAutoRegisterBaseReqDTO.getRegisterChannel() == null ? null : assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc(),assetAutoRegisterBaseReqDTO.getIdCard());
            registerRespDTO.setRegisterRespEnum(AssetAutoRegisterRespDTO.AssetAutoRegisterRespEnum.MOBILE_NOT_REGISTER_BUT_IDCARD_IS_USED);
            return registerRespDTO;

        }

    }

    private AssetAutoRegisterRespDTO updateAuthInfo(AssetAutoRegisterBaseReqDTO assetAutoRegisterBaseReqDTO,
                                                    AssetAutoRegisterRespDTO registerRespDTO, String encryptIdCard, String userId) {
        boolean verifyInfo = userIdentityService.tryUpdateAuthInfoByReamNameAuth(userId,assetAutoRegisterBaseReqDTO.getRealName(),
                encryptIdCard,assetAutoRegisterBaseReqDTO.getIdCard());
        if(verifyInfo){
            log.info(assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc()+"-用户已存在你我金融,用户身份信息(二要素)均已认证通过并入库!");
            registerRespDTO.setRegisterRespEnum(AssetAutoRegisterRespDTO.AssetAutoRegisterRespEnum.SUCCESS);
            registerRespDTO.setUserId(userId);
            return registerRespDTO;
        }else{
            log.error(assetAutoRegisterBaseReqDTO.getRegisterChannel().getDesc()+"用户手机号码(加密)mobileNo:{} 已注册,但用户实名信息[IdCard:{},RealName:{}]更新失败",
                    assetAutoRegisterBaseReqDTO.getIdCard(),encryptIdCard,assetAutoRegisterBaseReqDTO.getRealName());
            registerRespDTO.setRegisterRespEnum(AssetAutoRegisterRespDTO.AssetAutoRegisterRespEnum.USER_AUTH_INFO_UPDATE_ERROR);
            return registerRespDTO;
        }
    }


    private String doAutoRegistr(AssetAutoRegisterBaseReqDTO assetAutoRegisterBaseReqDTO, String encryptMobileNo) {
        // 账号映射
        LoginAccountMapping accountMapping = EntityBuilder.buildLoginAccountMapping(UUID.randomUUID().toString(), encryptMobileNo);

        // 用户账号
        UcAccount account = EntityBuilder.buildLoginAccount(accountMapping,
                assetAutoRegisterBaseReqDTO.getSalt(), assetAutoRegisterBaseReqDTO.getPassword());

        // 基础信息
        UserBasicInfo basicInfo = EntityBuilder.buildLoginAccountBasicInfo(accountMapping,
                assetAutoRegisterBaseReqDTO.getRegisterChannel(),null,generateNiiwooNickname(),randomGetSystemHeader(), info -> {
                    UpdateUserInfoRequest request = new UpdateUserInfoRequest();
                    request.setGuid(info.getUserId());
                    request.setMobile(assetAutoRegisterBaseReqDTO.getRegisterMobile());//拉取你我号,手机号码不加密
                    request.setPassword(assetAutoRegisterBaseReqDTO.getPassword());
                    request.setNickname(info.getNickName());
                    request.setAvatar(info.getHeadImage());
                    request.setGender((byte)UserEnum.Gender.UNKNOWN.getValue());
                    return updateUserInfoIM(request);
        });

        // 扩展信息
        UserExtInfo extInfo = EntityBuilder.buildLoginAccountExtInfo(accountMapping, assetAutoRegisterBaseReqDTO);

        // 认证信息
        UserAuthorizationInfo authorizationInfo = EntityBuilder.buildLoginAccountAuthorizationInfo(accountMapping);

        //你我分
        NiiwooScore score = EntityBuilder.buildNiiwooScore(snowflakeIdWorker.nextId(),accountMapping);

        boolean isSuccess = userLoginAccountLocalService.initAccountAndBasicInfo(accountMapping, account, basicInfo,
                extInfo,Optional.empty(),authorizationInfo,score);
        if (isSuccess) {
            // 天秤数据回流
            CompletableFuture.runAsync(() -> {
                RegisterSuccessRequest registerSuccessRequest = new RegisterSuccessRequest();
                registerSuccessRequest.setUserId(accountMapping.getUserId());
                registerSuccessRequest.setUserNickName(basicInfo.getNickName());
                registerSuccessRequest.setUserAccount(basicInfo.getNiiwooCode());
                registerSuccessRequest.setAvatar(basicInfo.getHeadImage());
                //0 非实名用户, 1 实名认证, 2 钱大保, 4 钱小保, 8借款人, 16合伙人, 32 有业人士, 64 学生用户
                registerSuccessRequest.setUserStatus(0);
                registerSuccessRequest.setUserName(assetAutoRegisterBaseReqDTO.getRegisterMobile());
                registerSuccessRequest.setMobilePhone(assetAutoRegisterBaseReqDTO.getRegisterMobile());
                //1 平台, 2 用户, 3 银行, 4 风险基金
                registerSuccessRequest.setUserType(2);
                registerSuccessRequest.setRegisterTime(System.currentTimeMillis() * 1000L);
                ////用户来源(0-未知 1团贷网，2好帮贷，3你我金融，4房宝宝，5现金动车，6量化派 7 借钱快 8 融360 9卡牛)
                registerSuccessRequest.setFromType(TCFromTypeEnum.getTCFromTypeFromRegisterChannel(assetAutoRegisterBaseReqDTO.getRegisterChannel()));
                userDataBackFlowService.regiserSuccess(registerSuccessRequest);
            });
        }
        return isSuccess ? accountMapping.getUserId() : null;
    }

    /**
     * 用户二要素验证,请求天秤接口,超时抛出异常
     * @param assetAutoRegisterBaseReqDTO
     * @return 验证通过返回true, 否则返回false
     */
    private boolean verifyIdCardAndNameByTiancheng(AssetAutoRegisterBaseReqDTO assetAutoRegisterBaseReqDTO) {
        KaoLaVerNameRequset req = new KaoLaVerNameRequset();

        req.setRealName(assetAutoRegisterBaseReqDTO.getRealName());
        req.setIdentityCard(assetAutoRegisterBaseReqDTO.getIdCard());
        req.setFunctionCode(FunctionCodeEnum.KAOLA_QUERY_VERIFY_ID_NAME.getBodyFunctionCode());
        req.setIsNew("0");
        req.setTransDate(new Date());
        req.setTransNo(String.valueOf(System.currentTimeMillis()));

        KaoLaVerNameResponse resp = null;
        try {
            CompletableFuture<KaoLaVerNameResponse> future = tianchengVerNameService.tianchengKaoLaVerName(req);
            resp = future.get(5L, TimeUnit.SECONDS);
            log.info("天秤二要素验证，request:{}, response:{}", JSON.toJSONString(req), JSON.toJSONString(resp));

            if (ObjectUtils.allNotNull(resp.getTianChengStatus(), resp.getResult())) {
                return KaoLaVerNameResponse.TianChengStatusEnum.SUCCESS.getCode().equals(resp.getTianChengStatus())
                        && KaoLaVerNameResponse.ResultEnum.VALID.getCode().equals(resp.getResult());
            } else {
                return false;
            }
        } catch (Exception e) {
            log.error("天秤二要素验证出错，request:{}, response:{}", JSON.toJSONString(req), JSON.toJSONString(resp), e);
            return false;
        }
    }

}
